`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 		PI3
// Engineer: 		Matthias Niethammer
// 
// Create Date:   	21:57:06 02/06/2010 
// Design Name: 	pulser
// Module Name:   	pulser 
// Project Name: 	pulser
// Target Devices:	Spartan XC3S1200E,FT256,-4
// Tool versions: 	ISE 11.1
// Description: 	Pulse Generator
//
// Dependencies:	okHost-modules okWireIn, okPipeIn and okTriggerIn
//
// Revision: 		Revision 0.03 - DDR w/ pipe connection to host
//
// Additional
// Comments: 		not tested yet
//
//////////////////////////////////////////////////////////////////////////////////
module pulser(
			input clk_in,
			
			/*** Oscilloscope ***/
			output data0_out,
			output data1_out,
			output data_out,
			output clk_out0,
			output clk_out1,
			/*** Oscilloscope ***/
			
			/*** LED connections ***
			,
			output [3:0] led
			*** LED connections ***/
			
			/*** okHost connections ***/
			input	wire [7:0]	hi_in,
			output	wire [1:0]	hi_out,
			inout	wire [15:0]	hi_inout,
			output	wire		i2c_sda,
			output	wire		i2c_scl,
			output	wire		hi_muxsel
			/*** okHost connections ***/
    );
	


/*** divided clock ***
	reg [25:0] div;
	reg d_clk0;

	always@( posedge clk_in )
	begin	
		div <= div-1;
		if( div == 0 )
		begin
			d_clk0 <= ~d_clk0;
		end
	end

wire clk0;
wire clk1;

wire d_clk1;
assign d_clk1 = ~d_clk0;

assign clk0 = d_clk0;
assign clk1 = d_clk1;

assign clk_out0 = d_clk0;
assign clk_out1 = d_clk1;
*** divided clock ***/




/*** 2nd clock ***/

wire clk1;
assign clk0 = clk_in;
assign clk1 = ~clk_in;						//maybe use DCM, better clk-skew?
assign clk_out0 = clk0;
assign clk_out1 = clk1;

/*** 2nd clock ***/



/*** state machine ***/
wire [15:0] trigger_out;
wire [15:0] wire_out;		//16bit control data from host
wire [1:0] ctrl_states;		//controls state machine
wire [1:0] RAM_sel;			//select 1 of 4 RAMs to write
wire w_addr_rst;			//resets write counter to 0

//controlled by host
assign ctrl_states[1:0] = wire_out[1:0];
assign RAM_sel[1:0] = wire_out[3:2];
assign w_addr_rst = trigger_out[0];

//COUNT
wire cnt_enable;		//enables pulse generation by enabling the counter

//WRITE
wire w_clk;				//48MHz from USB, connected to okHI-output
wire data_transfer; 	//enable data transfer mode
wire pipe_has_data;		//high when valid data on pipe out

//connections to RAM write_enables
wire write_data0;
wire write_data1;
wire write_t_data0;
wire write_t_data1;

//output of write counter
wire [9:0] w_cnt_out;

//connections from address-multiplexer to RAM write_addresses
wire [9:0] data0_write_adress;
wire [9:0] data1_write_adress;
wire [9:0] t_data0_write_adress;
wire [9:0] t_data1_write_adress;

//connections to route pipe output
wire [15:0] data0_input;
wire [15:0] data1_input;
wire [15:0] t_data0_input;
wire [15:0] t_data1_input;

//state machine instantiation
state_machine ctrl_state( ctrl_states[1:0],
							cnt_enable,
							data_transfer);


wire w_to_RAM;
assign w_to_RAM = data_transfer & pipe_has_data;		//only write, when both data availible and mode "load" set
 
/*** state machine ***/



/*** pipe routing ***/

wire [15:0] pipe_data;			//pipe output

//
counter w_addr_cnt(w_clk, w_to_RAM,w_addr_rst, w_cnt_out[9:0] );

mux_4 #(.N(10)) address_switch( data0_write_adress[9:0],
								data1_write_adress[9:0],
								t_data0_write_adress[9:0],
								t_data1_write_adress[9:0],
								w_cnt_out[9:0],
								RAM_sel[1:0]
								);

mux_4 #(.N(1)) write_enable_switch( write_data0,
								write_data1,
								write_t_data0,
								write_t_data1,
								w_to_RAM,
								RAM_sel[1:0]
								);
mux_4 #(.N(16)) pipe_in_switch( data0_input[15:0],
								data1_input[15:0],
								t_data0_input[15:0],
								t_data1_input[15:0],
								pipe_data[15:0],
								RAM_sel[1:0]
								);

/*** pipe routing ***/

/*** data adressing ***/

wire [15:0] data;
wire [15:0] data0;
wire [15:0] data1;
wire [9:0] d_addr0;							//RAM adress that'll be read next
wire [9:0] d_addr1;
wire d_addr_up0;							//selects next dataRAM adress when high
wire d_addr_up1;
wire d_addr_over0;							//high while d_addr_cnt overflow
wire d_addr_over1;


assign data0_out = data0[0];				//JP3-30
assign data1_out = data1[0];				//JP3-32
assign data_out = data[0];					//JP3-34



/*** debugging outputs ***
assign led[0] = clk0;
assign led[1] = clk1;
assign led[2] = d_clk0;
assign led[3] = d_clk1;
*** debugging outputs ***/


// data RAM0
addr_up_logic data0_logic( clk0, d_addr_up0, d_addr0[9:0], d_addr_over0);

// data RAM1
addr_up_logic data1_logic( clk1, d_addr_up1, d_addr1[9:0], d_addr_over1);
/*** data adressing ***/



/*** t_data adressing ***/

wire [9:0] t_data_addr0;						//signal on t_cnt_ROM_ADDRIN
wire [9:0] t_data_addr1;
wire t_data_addr_up0;						//high:loads next timecode into buffer
wire t_data_addr_up1;
wire t_data_addr_over0;
wire t_data_addr_over1;

//t_data0
addr_up_logic t_data0_logic( clk0, t_data_addr_up0, t_data_addr0[9:0], t_data_addr_over0); 

//t_data1
addr_up_logic t_data1_logic( clk1, t_data_addr_up1, t_data_addr1[9:0], t_data_addr_over1); 

/*** t_data adressing ***/


/*** t_cnt adressing ***/

wire [15:0] t_cnt_rom0;
wire [15:0] t_cnt_rom1;
wire [9:0] t_cnt_addr0;						//next address 
wire [9:0] t_cnt_addr1;	
wire [9:0] t_cnt_value0;					//contains current counter position
wire [9:0] t_cnt_value1;
wire [9:0] t_data0;						// [9:0]: pulselength for next puls
wire [9:0] t_data1;
wire t_addr_src_sel0;						//sets t_cnt_value (low) or tdata (high) as next t_cnt_addr
wire t_addr_src_sel1;					

assign t_cnt_value0[9:0] = t_cnt_rom0[9:0];
assign t_addr_src_sel0 = t_cnt_rom0[10];
assign t_data_addr_up0 = t_cnt_rom0[11];
assign d_addr_up0 = t_cnt_rom0[12];

assign t_cnt_value1[9:0] = t_cnt_rom1[9:0];
assign t_addr_src_sel1 = t_cnt_rom1[10];
assign t_data_addr_up1 = t_cnt_rom1[11];
assign d_addr_up1 = t_cnt_rom1[12];

addr_mux t_cnt_mux0(
			t_cnt_value0[9:0],
			t_data0[9:0],
			t_addr_src_sel0,
			t_cnt_addr0[9:0]
);

addr_mux t_cnt_mux1(
			t_cnt_value1[9:0],
			t_data1[9:0],
			t_addr_src_sel1,
			t_cnt_addr1[9:0]
);


or_16 out_mux(
		data0[15:0],
		data1[15:0],
		data[15:0]
);

/*** t_cnt adressing ***/




/*** time counter ***/

counter_ROM t_cnt_ROM0( cnt_enable,clk0,t_cnt_addr0[9:0],t_cnt_rom0[15:0]);
counter_ROM t_cnt_ROM1( cnt_enable,clk1,t_cnt_addr1[9:0],t_cnt_rom1[15:0]);

/*** time counter***/

/*** time data ***/

t_RAM_S18_S18 t_data_RAM0( clk0, w_clk, t_data_addr0[9:0],
						t_data0_write_adress[9:0],
						t_data0[9:0],
						t_data0_input[15:0],
						write_t_data0);
						
t_RAM_S18_S18 t_data_RAM1( clk1, w_clk, t_data_addr1[9:0],
						t_data1_write_adress[9:0],
						t_data1[9:0],
						t_data1_input[15:0],
						write_t_data1);
						
/*** time data ***/



/*** data ***/
	
d_RAM_S18_S18 data_RAM0( clk0, w_clk, d_addr0[9:0],
						data0_write_adress[9:0],
						data0[15:0],
						data0_input[15:0],
						write_data0);
						
d_RAM_S18_S18 data_RAM1( clk1, w_clk, d_addr1[9:0],
						data1_write_adress[9:0],
						data1[15:0],
						data1_input[15:0],
						write_data1);

/*** data ***/

/*** host interface ***/
host_interface USB( hi_in[7:0],
					hi_out[1:0],
					hi_inout[15:0],
					i2c_sda,
					i2c_scl,
					hi_muxsel,
					w_clk,
					pipe_data[15:0],
					pipe_has_data,
					wire_out[15:0],
					trigger_out[15:0]
			);
/*** host interface ***/

endmodule
